package com.jintian.smart.kernel.flowable.controller;

import com.jintian.smart.kernel.core.flow.ITaskOperation;
import com.jintian.smart.kernel.core.flow.ProcessControl;
import com.jintian.smart.kernel.core.web.RestResultWrapper;
import com.jintian.smart.kernel.flowable.api.PermissionService;
import com.jintian.smart.kernel.flowable.common.utils.BeanUtils;
import com.jintian.smart.kernel.flowable.domain.entity.ActHiTaskInst;
import com.jintian.smart.kernel.flowable.flowable.service.impl.TaskQueryHandler;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

/**
 * 流程任务相关
 */
@RestResultWrapper
@RestController
@RequestMapping("/flow/task")
@Schema(description = "流程任务")
@Transactional
public class TaskController {
    @Autowired
    private ITaskOperation<List<TaskInfo>> taskOperation;
    @Autowired
    private TaskQueryHandler taskQueryHandler;
    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private PermissionService permissionService;

    @RequestMapping(value = "/ownTaskInfo", method = RequestMethod.GET)
    @ResponseBody
    @Operation(summary = "获取任务实例")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID")})
    public Object ownTaskInfo(String taskId) throws Exception {
        Task task = taskQueryHandler.ownTask(taskId);
        if (task == null) {
            return null;
        }

        ProcessInstance pi = processEngine.getRuntimeService().createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).singleResult();
        ActHiTaskInst vo = BeanUtils.copyBean(task, ActHiTaskInst.class);
        vo.setProcessDefinitionKey(pi.getProcessDefinitionKey());
        vo.setProcessLabel(pi.getName());
        return vo;
    }

    @RequestMapping(value = "/suspend", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "任务挂起")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object suspend(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        List<TaskInfo> ret = taskOperation.suspend(taskId, processControl);
        return BeanUtils.copyList(ret, ActHiTaskInst.class);
    }

    @RequestMapping(value = "/resume", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "任务解挂")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object resume(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        List<TaskInfo> ret = taskOperation.resume(taskId, processControl);
        return BeanUtils.copyList(ret, ActHiTaskInst.class);
    }

    @RequestMapping(value = "/complete", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "任务完成")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object complete(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        List<TaskInfo> ret = taskOperation.complete(taskId, processControl);
        return BeanUtils.copyList(ret, ActHiTaskInst.class);
    }

    @RequestMapping(value = "/claim", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "任务签收")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object claim(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        taskOperation.claim(taskId, processControl);
        return "执行成功";
    }

    @RequestMapping(value = "/unclaim", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "撤销签收")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object unclaim(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        taskOperation.unclaim(taskId, processControl);
        return "执行成功";
    }

    @RequestMapping(value = "/transform", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "转发")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object transform(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        List<TaskInfo> ret = taskOperation.transform(taskId, processControl);
        return BeanUtils.copyList(ret, ActHiTaskInst.class);
    }

    @RequestMapping(value = "/fallback", method = RequestMethod.POST)
    @Operation(summary = "任务回退")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object fallback(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        List<TaskInfo> ret = taskOperation.fallback(taskId, processControl);
        return BeanUtils.copyList(ret, ActHiTaskInst.class);
    }

    @RequestMapping(value = "/withdraw", method = RequestMethod.POST)
    @Operation(summary = "任务取回")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "processControl", in = ParameterIn.DEFAULT, description = "流程控制")})
    public Object withdraw(String taskId, @Nullable @RequestBody ProcessControl processControl) throws Exception {
        taskOperation.withdraw(taskId, processControl);
        return "执行成功";
    }

    @RequestMapping(value = "/formUrl", method = RequestMethod.GET)
    @Operation(summary = "获取任务表单url")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID")})
    public String formUrl(@RequestParam("taskId") String taskId) throws Exception {
        return taskOperation.formUrl(taskId);
    }

    @RequestMapping(value = "/queryProcessControl", method = RequestMethod.POST)
    @ResponseBody
    @Operation(summary = "查询任务控制")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID"),
            @Parameter(name = "action", in = ParameterIn.DEFAULT, description = "流程动作"),
            @Parameter(name = "transientVariables", in = ParameterIn.DEFAULT, description = "流程变量")})
    public ProcessControl queryProcessControl(String taskId, String action, @Nullable @RequestBody Map<String, Object> transientVariables) throws Exception {
        return taskOperation.queryProcessControl(taskId, action, transientVariables);
    }

    @RequestMapping(value = "/queryExecutors", method = RequestMethod.GET)
    @ResponseBody
    @Operation(summary = "查询任务执行者")
    @Parameters(value = {@Parameter(name = "taskId", in = ParameterIn.DEFAULT, description = "任务ID")})
    public Object queryExecutors(String taskId) {
        TaskEntity task = (TaskEntity) this.processEngine.getTaskService().createTaskQuery().taskId(taskId)
                .includeIdentityLinks().singleResult();
        if (task == null) {
            throw new IllegalArgumentException("不存在id为" + taskId + "任务实例");
        } else {
            return permissionService.getCanExecutor(task);
        }
    }
}
